package com.ttxs.utils.csv;

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.text.StringEscapeUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;


/**
 * CSV工具类   格式转换、格式验证、格式化功能
 *
 * @author xsb
 */

public class CsvUtils {

    private static void begin(String inputPath) {
        if (!csvValidator(inputPath)) {
            //这里输出提示（实际应抛出异常，前端捕获提示用户）
            System.out.println("CSV文件格式错误");
        }
    }

    /***
     *实现CSV转JSON
     * @param inputPath 文件地址
     * @param outputPath 输出文件地址
     * @author xsb
     */

    public static void csv2Json(String inputPath, String outputPath) {
        begin(inputPath);
        int hang = 0;    //行数标记
        StringBuilder jsonStr;    //转换结果json字符串
        String[] keys = new String[0];    //属性名容器
        String[] vals;

        CSVReader reader = null;
        try {
            reader = new CSVReader(new FileReader(inputPath));
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在");
        }
        File outputFile = new File(outputPath);    //写入文件，若没有则创建
        FileWriter fw = null;
        try {
            //以追加的方式写入文件
            fw = new FileWriter(outputFile, true);
            fw.write("[\n");
        } catch (IOException e) {
            System.out.println("文件写入失败");
        }
        boolean flag = false;
        while (true) {
            try {
                jsonStr = new StringBuilder();
                vals = reader.readNext();
                if (vals == null) break;   //没有下一行，退出
                hang++;    //行数自增
                if (hang == 1) {    //第一行是属性名,属性名应该做标签
                    keys = vals.clone();    //把属性名拿出来
                    continue;
                }
                for (int k = 0; k < keys.length; k++) {
                    if (!(keys[k].startsWith("\"") && keys[k].endsWith("\""))) {
                        keys[k] = "\"" + keys[k] + "\"";    //给没引号包裹的加上引号
                    }
                }
                int i = 0;
                jsonStr.append("\t{\n\t\t");    //一组参数头的缩进与大括号并换行和下一行缩进
                while (i < keys.length) {

                    try {
                        // 尝试将字符串转换为浮点数
                        Double.parseDouble(vals[i]);
                    } catch (NumberFormatException e1) {    //转换失败加引号
                        flag = true;
                    }

                    if ("true".equalsIgnoreCase(vals[i])) {
                        flag = false;
                        vals[i] = "true"; //json中只能识别小写的 true false
                    }
                    if ("false".equalsIgnoreCase(vals[i])) {
                        flag = false;
                        vals[i] = "false";
                    }
                    if (flag) {    //有引号不转换
                        if (vals[i].startsWith("\"") && vals[i].endsWith("\"")) {
                            continue;
                        } else {
                            vals[i] = "\"" + vals[i] + "\"";    //给没引号包裹的加上引号
                        }
                        flag = false;
                    }
                    jsonStr.append(keys[i].trim()).append(" : ").append(vals[i].trim());
                    if (i == keys.length - 1) {
                        jsonStr.append("\n");    //一组参数里最后一个参数，不要逗号，换行
                    } else {
                        jsonStr.append(",\n\t\t");    //逗号分割同一组的不同参数并换行和下一行缩进
                    }
                    i++;
                }
                jsonStr.append("\t},\n");    //一组参数结尾的大括号和逗号并换行
                if (fw != null) {   //防止上面代码发生异常程序不停止
                    fw.write(String.valueOf(jsonStr));
                } else {
                    System.out.println("FileWriter为空");
                }
            } catch (CsvValidationException e) {
                System.out.println("不符合csv格式要求");
            } catch (IOException e) {
                System.out.println("文件写入异常");
            }
        }
        try {
            reader.close();
            fw.close();
            RandomAccessFile rw = new RandomAccessFile(outputPath, "rw");
            rw.setLength(rw.length() - 2);
            rw.close();
        } catch (IOException e) {
            System.out.println("文件写入失败");
        }
        if (hang != 0) {    //不是空文件
            FileWriter fwm;
            try {
                fwm = new FileWriter(outputFile, true);
                fwm.write("\n]");
                fwm.close();
            } catch (IOException e) {
                System.out.println("文件写入异常");
            }
        }
    }

    /***
     *实现CSV转XML
     * @param inputPath 文件地址
     * @param outputPath 输出文件地址
     * @return 返回转化好的xml字符串
     * @author xsb
     */

    public static void csv2Xml(String inputPath, String outputPath) {
        begin(inputPath);
        int hang = 0;    //行数容器
        StringBuilder xmlStr;    //结果
        String[] keys = new String[0];    //属性名容器
        String[] vals;

        CSVReader reader = null;
        try {
            reader = new CSVReader(new FileReader(inputPath));
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在");
        }
        File t = new File(outputPath);    //写入文件，若没有则创建
        FileWriter fw = null;
        try {
            fw = new FileWriter(t, true);
            fw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");  //文件头，换行
            fw.write("<dataset>\n");  //全部数据的开始标签，换行
        } catch (IOException e) {
            System.out.println("文件写入失败");
        }
        while (true) {
            try {
                xmlStr = new StringBuilder();
                vals = reader.readNext();
                if (vals == null) break;
                hang++;    //行数自增
                if (hang == 1) {    //第一行是属性名,属性名应该做标签
                    keys = vals.clone();    //把属性名拿出来
                    continue;
                }
                int i = 0;
                xmlStr.append("\t<record>\n");    //缩进，一组数据的开始标签，换行
                while (i < keys.length) {
                    //xml中标签只能包含 字母，数字，冒号，连字符，下划线
                    String tag = keys[i].replaceAll("[^\\w:-]", "_");
                    //xml中值 中如果包含 <  &  则需要进行转义
                    String val = StringEscapeUtils.escapeXml10(vals[i]);
                    xmlStr.append("\t\t<").append(tag).append(">").append(val).append("</").append(tag).append(">\n");
                    i++;
                }
                xmlStr.append("\t</record>\n");    //缩进，一组数据的结束标签，换行
                fw.write(String.valueOf(xmlStr));
            } catch (CsvValidationException e) {
                System.out.println("不符合csv格式要求");
            } catch (IOException e) {
                System.out.println("文件写入异常");
            }
        }
        try {
            reader.close();
            fw.write("</dataset>");    //全部数据的结束标签
            fw.close();
        } catch (IOException e) {
            System.out.println("文件写入异常");
        }
    }


    /***
     *实现JSON转XML
     * @param inputPath 文件地址
     * @param outputPath 输出文件地址
     * @return 返回转化好的yaml字符串
     * @author xsb
     */

    public static void csv2Yaml(String inputPath, String outputPath) {
        begin(inputPath);
        int hang = 0;    //行数容器
        StringBuilder yamlStr;    //结果
        String[] keys = new String[0];    //属性名容器
        String[] vals;

        CSVReader reader = null;
        try {
            reader = new CSVReader(new FileReader(inputPath));
        } catch (FileNotFoundException e) {
            System.out.println("输出文件不存在");
        }
        File t = new File(outputPath);    //写入文件，若没有则创建
        FileWriter fw = null;
        try {
            fw = new FileWriter(t, true);
        } catch (IOException e) {
            System.out.println("文件写入异常");
        }
        while (true) {
            try {
                yamlStr = new StringBuilder();
                vals = reader.readNext();
                if (vals == null) break;
                hang++;    //行数自增
                if (hang == 1) {    //第一行是属性名,属性名应该做标签
                    keys = vals.clone();    //把属性名拿出来
                    continue;
                }
                int i = 0;
                yamlStr.append("-");    //一组数据的头
                while (i < keys.length) {
                    if (i == 0) {
                        yamlStr.append(" ");   //一组数据的头的比接下来的少缩进一格
                    } else {
                        yamlStr.append("  ");
                    }
                    yamlStr.append(keys[i]).append(": ").append(vals[i]).append("\n");    //缩进，键值对key: value，换行
                    i++;
                }
                fw.write(String.valueOf(yamlStr));
            } catch (CsvValidationException e) {
                System.out.println("不符合csv格式要求");
            } catch (IOException e) {
                System.out.println("输出文件写入异常");
            }
        }
        try {
            reader.close();
            if (fw != null) {
                fw.close();
            } else {
                System.out.println();
            }
        } catch (IOException e) {
            System.out.println("文件写入异常");
        }
    }

    /***
     *实现CSV格式验证
     * @param inputPath 文件地址
     * @author xsb
     */

    public static boolean csvValidator(String inputPath) {
        try (CSVReader reader = new CSVReader(new FileReader(inputPath))) {
            String[] headers = reader.readNext();
            if (headers == null || headers.length == 0) {
//                System.out.println("CSV文件头部为空.");
                return false;
            }

            int expectedNumColumns = headers.length;

            String[] record;
            while ((record = reader.readNext()) != null) {
                if (record.length != expectedNumColumns) {

//                    System.out.println("CSV文件的行 " + reader.getLinesRead() + " 列数与头部不匹配.");
                    return false;
                }
            }

            return true;
        } catch (IOException | CsvValidationException e) {
            return false;
        }

    }
    

    /***
     *实现CSV格式规范
     * @param inputPath 文件地址
     * @param outputPath 输出文件地址
     * @author xsb
     */

    public static void csvFormatter(String inputPath, String outputPath) {
        begin(inputPath);
        // 设置 CSV 格式
        CSVFormat csvFormat = CSVFormat.RFC4180.withFirstRecordAsHeader();

        // 设置输入文件和输出文件
        File inputFile = new File(inputPath);
        File outputFile = new File(outputPath);

        // 设置输入文件和输出文件的流
        try (Reader reader = new BufferedReader(new FileReader(inputFile));
             Writer writer = new BufferedWriter(new FileWriter(outputFile));
             CSVParser csvParser = new CSVParser(reader, csvFormat);
             CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) {

            // 处理表头
            String[] csvHeader = csvParser.getHeaderMap().keySet().toString().replace("[", "").replace("]", "").split(",");
            int j = 0;
            while (j < csvHeader.length) {
                csvHeader[j] = csvHeader[j].trim();
                j++;
            }
            csvPrinter.printRecord((Object) csvHeader);

            // 处理数据行
            List<CSVRecord> records = csvParser.getRecords();
            for (CSVRecord record : records) {
                List<String> normalizedRow = new ArrayList<>();
                // 处理每个单元格
                for (int i = 0; i < record.size(); i++) {
                    String cellValue = record.get(i);
                    if (cellValue == null || cellValue.isEmpty()) {
                        normalizedRow.add("null");
                    } else {
                        normalizedRow.add(cellValue.trim());
                    }
                }
                while (normalizedRow.size() != csvParser.getHeaderMap().size()) {
                    normalizedRow.add("null");
                }
                csvPrinter.printRecord(normalizedRow);
            }
        } catch (IOException e) {
            System.out.println("文件写入异常");
        }
    }
}